﻿#region Using

using System;
using XNgine.Services;

#endregion

namespace XNgine.ScreenManagement
{
    public abstract class GameScreen : IGameScreen
    {
        #region Properties

        #region Blocking Operation

        /// <summary>
        /// Whether or not this screen should block the update of
        /// screens below (for pause menus), etc.
        /// </summary>
        public bool BlocksUpdate { get; set; }

        /// <summary>
        /// Whether or not this screen should block the draw of
        /// screens below (for pause menus), etc.
        /// </summary>
        public bool BlocksDraw { get; set; }

        /// <summary>
        /// Whether or not this screen should block the input processing of
        /// screens below (for pause menus), etc.
        /// </summary>
        public bool BlocksInput { get; set; }

        #endregion

        #region Overriding Block Operation

        /// <summary>
        /// Whether or not this screen will override a blocked update
        /// from an above screen (for a background screen), etc.
        /// </summary>
        public bool OverrideUpdateBlocked { get; set; }

        /// <summary>
        /// Whether or not this screen will override a blocked draw
        /// from an above screen (for a background screen), etc.
        /// </summary>
        public bool OverrideDrawBlocked { get; set; }

        /// <summary>
        /// Whether or not this screen will override a blocked input
        /// from an above screen (for a background screen), etc.
        /// </summary>
        public bool OverrideInputBlocked { get; set; }

        #endregion

        #region Loading and Initialization
        public bool ContentLoaded { get; set; }

        private bool inititalized;

        /// <summary>
        /// Whether or not the screen is initialized. Handles firing of
        /// OnInitialized.
        /// </summary>
        public bool Initialized
        {
            get { return inititalized; }
            set
            {
                inititalized = value;
                if (OnInitialized != null)
                {
                    // Fire the OnInitalized event to let other's know we
                    // are done initializing
                    OnInitialized(this, new EventArgs());
                }
            }
        }

        #endregion

        #region Visibility

        public bool Visible { get; set; }

        #endregion

        #region Input

        /// <summary>
        /// Whether or not we want to block our own input so we can
        /// do things like loading screens that will want to accept
        /// input at some point, but not at startup
        /// </summary>
        public bool InputDisabled { get; set; }

        /// <summary>
        /// Indicates if the screen is allowed to process input
        /// (Updated ad every frame)
        /// </summary>
        public bool IsInputAllowed { get; set; }

        #endregion

        #region INamedItem Members

        /// <summary>
        /// The name of the screen (a GameScreen can be accessed through the
        /// ScreenManager by using ScreenManager.Screens[Name])
        /// </summary>
        public string Name { get; private set; }

        #endregion

        #endregion

        #region Events

        /// <summary>
        /// Fired when the screen's Initialize() is finished. This can
        /// be hooked for things like asynchronous loading screens
        /// </summary>
        public event EventHandler OnInitialized;

        #endregion

        #region Loading and Initialization

        /// <summary>
        /// Constructs a GameScreen with specified name
        /// </summary>
        protected GameScreen(string name)
        {
            // Register with the engine and set our name
            this.Name = name;

            Initialize();
        }

        /// <summary>
        /// Overridable function to initialize the GameScreen
        /// (Remember to set the Initialized to true or call base.Initialize();)
        /// </summary>
        public virtual void Initialize()
        {
            Visible = true;

            if (Initialized) return;

            this.Initialized = true;
        }

        public virtual void LoadContent()
        {
            ContentLoaded = true;
        }

        public virtual void UnloadContent()
        {
            ContentLoaded = false;
        }

        #endregion

        #region Main loop

        /// <summary>
        /// Performs the update of the screen
        /// </summary>
        public abstract void Update();

        /// <summary>
        /// Perfroms the drawing of the screen
        /// </summary>
        public abstract void Draw();

        #endregion

        #region Core Functionality Methods

        /// <summary>
        /// Closes the GameScreen(removes it from the ScreenManager)
        /// </summary
        public void Close()
        {
            XEngine.Instance.GetService<IScreenManagement>().CloseScreen(this);
        }

        public void Show()
        {
            XEngine.Instance.GetService<IScreenManagement>().Show(this);
        }

        #endregion
    }
}